﻿/*
 * options.cpp
 *
 *  Created on: 2018年2月22日
 *      Author: turner
 */

#include <dm/export.hpp>

#define DM_API_OS_OPTIONS DM_API_EXPORT

#include <dm/os/options.hpp>
#include <dm/env/cfg.hpp>

#include <dm/os/log/logger.hpp>

#include <dm/os/db/db.hpp>
#include <dm/os/db/resultset.hpp>

namespace dm{
namespace env{

static const char* logModule = "COptions.env.dm";

using namespace dm::os;

static const char* d_group = "default";

COptions::COptions(){
	m_db = os::createDb(CCfg::ins().option_dbName().c_str(),CCfg::ins().option_dbHost().c_str(),CCfg::ins().option_dbEngine().c_str());
	if( !m_db->connect( CCfg::ins().option_dbUsr().c_str(),CCfg::ins().option_dbPwd().c_str()) )
		log().warnning(THISMODULE "不能连接数据库 %s:%s@%s.%s",CCfg::ins().option_dbEngine().c_str(),CCfg::ins().option_dbUsr().c_str(),
				CCfg::ins().option_dbHost().c_str(),
				CCfg::ins().option_dbName().c_str()
				);
}

COptions::~COptions(){
}

/**
 * 系统参数初始化
 * 若系统表不存在，则创建。否在清除系统表
 * @return 执行结果
 * - true 成功
 * - false 失败。一般是数据库连接有异常
 */
bool COptions::init(){
	m_db->exec("DROP TABLE IF EXISTS r_option");
	return m_db->exec("CREATE TABLE r_option (g_name varchar(64) NOT NULL, o_name varchar(64) NOT NULL, v_bool integer(1), v_int integer(11), v_float float(10), v_string varchar(255), PRIMARY KEY (g_name, o_name))");
}

/**
 * 增加系统配置选项
 * 若不存在该项目，会添加。若存在，原项目不会受影响
 * @param option 选项
 * @param group 分组
 * @return
 */
bool COptions::add( const char* option,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
#ifdef DB_MYSQL
	std::sprintf(sql,"insert ignore into r_option(g_name,o_name) values('%s','%s')",group,option);
#else
	std::sprintf(sql,"insert or ignore into r_option(g_name,o_name) values('%s','%s')",group,option);
#endif
	return m_db->exec(sql);
}

/**
 * 清除系统配置选项
 * 若group和option都为NULL，清除所有记录
 * 若option为NULL，清除组group的所有记录
 * @param option
 * @param group
 * @return
 */
bool COptions::clear( const char* option,const char* group ){
	char sql[128];
	if( group==NULL ){
		if( option==NULL ){
			std::sprintf(sql,"delete from r_option");
		}else{
			std::sprintf(sql,"delete from r_option where g_name='%s'",group);
		}
	}else{
		if( option==NULL )
			return false;

		std::sprintf(sql,"delete from r_option where g_name='%s' and o_name='%s'",group,option);
	}

	return m_db->exec(sql);
}

/**
 * 设置系统配置选项
 * @param option
 * @param value
 * @param group
 * @return
 */
bool COptions::set( const char* option,const bool& value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"update r_option set v_bool=%d where g_name='%s' and o_name='%s'",value?1:0,group,option);

	return m_db->exec(sql);
}

bool COptions::set( const char* option,const int& value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"update r_option set v_int=%d where g_name='%s' and o_name='%s'",value,group,option);

	return m_db->exec(sql);
}

bool COptions::set( const char* option,const float& value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"update r_option set v_float=%f where g_name='%s' and o_name='%s'",value,group,option);

	return m_db->exec(sql);
}

bool COptions::set( const char* option,const char* value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"update r_option set v_string='%s' where g_name='%s' and o_name='%s'",value,group,option);

	return m_db->exec(sql);
}

bool COptions::get( const char* option,bool& value,const char* group){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_bool from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));

	if( rs && rs->next() && (!rs->isNull(0))){
		value = rs->asBool(0);
		return true;
	}

	return false;
}

bool COptions::get( const char* option,int& value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_int from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) ){
		value = rs->asInt(0);
		return true;
	}

	return false;
}

bool COptions::get( const char* option,float& value,const char* group ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_float from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) ){
		value = rs->asDouble(0);
		return true;
	}

	return false;
}

bool COptions::get( const char* option,std::string& value,const char* group  ){
	if( option==NULL )
		return false;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_string from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) ){
		value = rs->asString(0);
		return true;
	}

	return false;
}

bool COptions::getBool( const char* option,const bool& defaultValue,const char* group ){
	if( option==NULL )
		return defaultValue;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_bool from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) )
		return rs->asBool(0);

	return defaultValue;
}

int COptions::getInt( const char* option,const int& defaultValue,const char* group ){
	if( option==NULL )
		return defaultValue;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_int from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) )
		return rs->asInt(0);

	return defaultValue;
}

float COptions::getFloat( const char* option,const float& defaultValue,const char* group ){
	if( option==NULL )
		return defaultValue;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_float from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) )
		return rs->asDouble(0);

	return defaultValue;
}

std::string COptions::getString( const char* option,const char* defaultValue,const char* group ){
	if( option==NULL )
		return defaultValue;
	if( group==NULL )
		group = d_group;

	char sql[128];
	std::sprintf(sql,"select v_string from r_option where g_name='%s' and o_name='%s'",group,option);

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));
	if( rs && rs->next()&& (!rs->isNull(0)) )
		return rs->asString(0);

	return defaultValue;
}

void COptions::show( const char* option,const char* group,std::ostream& ostr ){
	char sql[128];

	if( group==NULL ){
		if( option ){
			std::sprintf(sql,"select g_name,o_name,v_bool,v_int,v_float,v_string from r_option where o_name='%s' order by g_name",option);
		}else{
			std::sprintf(sql,"select g_name,o_name,v_bool,v_int,v_float,v_string from r_option order by g_name");
		}
	}else{
		if( option ){
			std::sprintf(sql,"select g_name,o_name,v_bool,v_int,v_float,v_string from r_option where g_name='%s' and o_name='%s' order by g_name",group,option);
		}else{
			std::sprintf(sql,"select g_name,o_name,v_bool,v_int,v_float,v_string from r_option where g_name='%s' order by g_name",group);
		}
	}

	dm::TScopedPtr<CResultSet> rs(m_db->query(sql));

	if( rs ){
		ostr <<"组\t|选项\t|布尔值\t|整数值\t|浮点数值\t|字符串值\n";
		while( rs->next() ){
			if( rs->isNull(0) )
				ostr <<"--";
			else
				ostr << rs->asString(0);
			ostr <<'|';

			if( rs->isNull(1) )
				ostr <<"--";
			else
				ostr << rs->asString(1);
			ostr <<'|';

			if( rs->isNull(2) )
				ostr <<"--";
			else
				ostr << rs->asBool(2);
			ostr <<'|';

			if( rs->isNull(3) )
				ostr <<"--";
			else
				ostr << rs->asInt(3);
			ostr <<'|';

			if( rs->isNull(4) )
				ostr <<"--";
			else
				ostr << rs->asDouble(4);
			ostr <<'|';

			if( rs->isNull(5) )
				ostr <<"--";
			else
				ostr << rs->asString(5);
			ostr <<'\n';
		}
	}
}

}
}


